package rpa

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"git.mycaigou.com/gfyx/common/cache"
	"git.mycaigou.com/gfyx/micro-gfyx-api/infrastructure/dto/rpa"
	"git.myscrm.cn/golang/stark/v4"
	"github.com/parnurzeal/gorequest"
	"net/url"
)

var (
	host                     = "https://open.byai.com"
	ByaiTokenPath            = "/oauth/token"
	ByaiTaskDetailPath       = "/api/oauth/byai.openapi.calljob.detail/1.0.0/get"
	GetByAiTaskListPath      = "/api/oauth/byai.openapi.calljob/1.0.0/list"
	DeleteByAiTaskPath       = "/api/oauth/byai.openapi.calljob/1.0.0/delete"
	ExecuteByAiTaskPath      = "/api/oauth/byai.openapi.calljob/1.0.0/execute"
	ImportCustomerToTaskPath = "/api/oauth/byai.openapi.calljob.customer/1.0.0/import"
	UpdateByAiTaskPath       = "/api/oauth/byai.openapi.calljob/1.0.0/update"
	CreateByAiTaskPath       = "/api/oauth/byai.openapi.calljob/1.0.0/create"
)

type ByaiRepository struct {
}

// 构造函数
func NewByaiRepository() ByaiRepositoryIface {
	return &ByaiRepository{}
}

// 获取白应token
func (r *ByaiRepository) GetByaiToken(ctx context.Context, companyId int64, appId, secret string) (string, error) {
	// 1. 检查cache是否有ak，有直接返回
	cacheRedis, _ := cache.Redis()
	cacheKey := fmt.Sprintf("gfyx-GetByaiToken-%d", companyId)
	ak, err := cacheRedis.Get(ctx, cacheKey)
	if err != nil {
		return "", err
	}

	stark.Logger.Infof(ctx, "GetByaiToken-from-cache: %s, err: %+v", ak, err)
	if ak != "" {
		return ak, nil
	}

	// 2. ak不存在，从白应ai获取
	request := gorequest.New()
	hostUrl := fmt.Sprintf("%s%s", host, ByaiTokenPath)
	paramsBody := fmt.Sprintf("client_id=%s&client_secret=%s&company_id=%d", appId, secret, companyId)
	stark.Logger.Infof(ctx, "before-GetByaiToken-url: %s, request: %s", hostUrl, paramsBody)
	var response rpa.GetByaiTokenJSONData
	_, body, errs := request.Post(hostUrl).
		AppendHeader("Content-Type", "application/x-www-form-urlencoded").
		Send(paramsBody).
		EndStruct(&response)

	stark.Logger.Infof(ctx, "after-GetByaiToken-url: %s, request: %s, body: %+v, errs: %+v", hostUrl, paramsBody, string(body), errs)
	if errs != nil && len(errs) > 0 {
		return "", errs[0]
	}

	if response.Code != 200 {
		return "", errors.New("获取token失败")
	}

	if response.Data == nil {
		return "", errors.New("获取token失败")
	}

	data := response.Data
	_, err = cacheRedis.Set(ctx, cacheKey, data.AccessToken, true, 10*60)
	if err != nil {
		return "", err
	}

	return data.AccessToken, nil
}

// 获取AI外呼任务详情, https://open.byai.com/document/get_229
func (r *ByaiRepository) GetByaiTaskDetail(ctx context.Context, callJobId int64, companyId int64) (*rpa.GetByaiTaskData, error) {
	ak, err := r.GetByaiToken(ctx, rpa.COMPANYID, rpa.APP_KEY, rpa.APP_SECRET)
	if err != nil {
		stark.Logger.Infof(ctx, "GetByaiTaskDetail-getak-err: %+v", err)
		return nil, err
	}

	request := gorequest.New()
	hostUrl := fmt.Sprintf("%s%s", host, ByaiTaskDetailPath)
	paramsBody := fmt.Sprintf("callJobId=%d&companyId=%d&accessToken=%s", callJobId, companyId, ak)

	stark.Logger.Infof(ctx, "before-GetByaiTaskDetail-url: %s, request: %s", hostUrl, paramsBody)
	var response rpa.GetByaiTaskJSONData
	_, body, errs := request.Post(hostUrl).
		AppendHeader("Content-Type", "application/x-www-form-urlencoded").
		Send(paramsBody).
		EndStruct(&response)

	stark.Logger.Infof(ctx, "after-GetByaiTaskDetail-url: %s, request: %s, body: %+v, errs: %+v", hostUrl, paramsBody, string(body), errs)
	if errs != nil && len(errs) > 0 {
		return nil, errs[0]
	}

	if response.Code != 200 {
		return nil, errors.New(response.ResultMsg)
	}

	if response.Data == nil {
		return nil, errors.New("获取任务详情失败")
	}

	return response.Data, nil
}

// 获取AI任务列表, https://open.byai.com/document/list_226
func (r *ByaiRepository) GetByAiTaskList(ctx context.Context, callJobStatus int8, companyId int64, createDate, endDate, jobName string, pageNum, pageSize int64) (*rpa.GetByAiTaskListData, error) {
	return nil, nil
}

// 删除ai任务, https://open.byai.com/document/delete_222
func (r *ByaiRepository) DeleteByAiTask(ctx context.Context, callJobId int64, companyId int64) (bool, error) {
	ak, err := r.GetByaiToken(ctx, rpa.COMPANYID, rpa.APP_KEY, rpa.APP_SECRET)
	if err != nil {
		stark.Logger.Infof(ctx, "GetByaiTaskDetail-getak-err: %+v", err)
		return false, err
	}

	request := gorequest.New()
	url := fmt.Sprintf("%s%s", host, DeleteByAiTaskPath)
	paramsBody := fmt.Sprintf("callJobId=%d&companyId=%d&accessToken=%s", callJobId, companyId, ak)

	stark.Logger.Infof(ctx, "before-DeleteByAiTask-url: %s, request: %s", url, paramsBody)
	var response rpa.DeleteByAiTaskResponse
	_, body, errs := request.Post(url).
		AppendHeader("Content-Type", "application/x-www-form-urlencoded").
		Send(paramsBody).
		EndStruct(&response)

	stark.Logger.Infof(ctx, "after-DeleteByAiTask-url: %s, request: %s, body: %+v, errs: %+v", url, paramsBody, string(body), errs)
	if errs != nil && len(errs) > 0 {
		return false, errs[0]
	}

	if response.Code != 200 {
		return false, errors.New(response.ResultMsg)
	}

	return true, nil
}

// 执行ai任务, https://open.byai.com/document/execute_221
func (r *ByaiRepository) ExecuteByAiTask(ctx context.Context, callJobId int64, companyId int64, command int32) (bool, error) {
	ak, err := r.GetByaiToken(ctx, rpa.COMPANYID, rpa.APP_KEY, rpa.APP_SECRET)
	if err != nil {
		stark.Logger.Infof(ctx, "GetByaiTaskDetail-getak-err: %+v", err)
		return false, err
	}

	request := gorequest.New()
	hostUrl := fmt.Sprintf("%s%s", host, ExecuteByAiTaskPath)
	paramsBody := fmt.Sprintf("callJobId=%d&companyId=%d&command=%d&accessToken=%s", callJobId, companyId, command, ak)

	stark.Logger.Infof(ctx, "before-ExecuteByAiTask-url: %s, request: %s", hostUrl, paramsBody)
	var response rpa.ExecuteByAiTaskResponse
	_, body, errs := request.Post(hostUrl).
		AppendHeader("Content-Type", "application/x-www-form-urlencoded").
		Send(paramsBody).
		EndStruct(&response)

	stark.Logger.Infof(ctx, "after-ExecuteByAiTask-url: %s, request: %s, body: %+v, errs: %+v", hostUrl, paramsBody, string(body), errs)
	if errs != nil && len(errs) > 0 {
		return false, errs[0]
	}

	if response.Code != 200 {
		return false, errors.New(response.ResultMsg)
	}

	return true, nil
}

// 向任务中导入客户
func (r *ByaiRepository) ImportCustomerToTask(ctx context.Context, callJobId int64, companyId int64, customerInfo []*rpa.CustomerInfoItem) (bool, error) {
	ak, err := r.GetByaiToken(ctx, rpa.COMPANYID, rpa.APP_KEY, rpa.APP_SECRET)
	if err != nil {
		stark.Logger.Infof(ctx, "GetByaiTaskDetail-getak-err: %+v", err)
		return false, err
	}

	request := gorequest.New()
	hostUrl := fmt.Sprintf("%s%s", host, ImportCustomerToTaskPath)
	data := url.Values{}
	data.Set("callJobId", fmt.Sprintf("%d", callJobId))
	data.Set("companyId", fmt.Sprintf("%d", companyId))
	customerInfoByteArray, err := json.Marshal(customerInfo)
	if err != nil {
		return false, err
	}
	data.Set("customerInfoVOList", string(customerInfoByteArray))
	data.Set("accessToken", ak)
	paramsBody := data.Encode()

	stark.Logger.Infof(ctx, "before-ImportCustomerToTask-url: %s, request: %s", hostUrl, paramsBody)
	var response rpa.ExecuteByAiTaskResponse
	_, body, errs := request.Post(hostUrl).
		AppendHeader("Content-Type", "application/x-www-form-urlencoded").
		Send(paramsBody).
		EndStruct(&response)

	stark.Logger.Infof(ctx, "after-ImportCustomerToTask-url: %s, request: %s, body: %+v, errs: %+v", hostUrl, paramsBody, string(body), errs)
	if errs != nil && len(errs) > 0 {
		return false, errs[0]
	}

	if response.Code != 200 {
		return false, errors.New(response.ResultMsg)
	}

	return true, nil
}

// ai外呼任务更新
func (r *ByaiRepository) UpdateByAiTask(ctx context.Context, params *rpa.ByAiTask) (bool, error) {
	return false, nil
}

// 创建ai外呼任务
func (r *ByaiRepository) CreateByAiTask(ctx context.Context, params *rpa.ByAiTask) (int64, error) {
	request := gorequest.New()
	hostUrl := fmt.Sprintf("%s%s", host, CreateByAiTaskPath)

	taskParams := url.Values{}
	taskParams.Set("callJobName", params.CallJobName)
	taskParams.Set("callJobType", fmt.Sprintf("%d", params.CallJobType))
	taskParams.Set("companyId", fmt.Sprintf("%d", params.CompanyId))
	taskParams.Set("concurrencyNum", fmt.Sprintf("%d", params.ConcurrencyNum))
	taskParams.Set("concurrencyQuota", fmt.Sprintf("%d", params.ConcurrencyQuota))
	taskParams.Set("remark", params.Remark)
	taskParams.Set("robotDefId", fmt.Sprintf("%d", params.RobotDefId))
	if params.PermitRepeatNum == true {
		taskParams.Set("permitRepeatNum", "true")
	}

	userPhoneIdsStr := ""
	for _, item := range params.UserPhoneIds {
		if userPhoneIdsStr == "" {
			userPhoneIdsStr = fmt.Sprintf("[%d", item)
		} else {
			userPhoneIdsStr = fmt.Sprintf("%s,%d", userPhoneIdsStr, item)
		}
	}

	if userPhoneIdsStr != "" {
		userPhoneIdsStr = fmt.Sprintf("%s]", userPhoneIdsStr)
	}

	taskParams.Set("userPhoneIds", userPhoneIdsStr)
	ak, err := r.GetByaiToken(ctx, rpa.COMPANYID, rpa.APP_KEY, rpa.APP_SECRET)
	if err != nil {
		stark.Logger.Infof(ctx, "CreateByAiTask-getak-err: %+v", err)
		return 0, err
	}
	taskParams.Set("accessToken", ak)
	taskParamsStr := taskParams.Encode()

	stark.Logger.Infof(ctx, "before-CreateByAiTask-url: %s, request: %+v", hostUrl, taskParamsStr)

	var response rpa.ByAiTaskResponse
	_, body, errs := request.Post(hostUrl).
		AppendHeader("Content-Type", "application/x-www-form-urlencoded").
		Send(taskParamsStr).
		EndStruct(&response)

	stark.Logger.Infof(ctx, "after-CreateByAiTask-url: %s, request: %+v, body: %+v, errs: %+v", hostUrl, taskParamsStr, string(body), errs)
	if errs != nil && len(errs) > 0 {
		return 0, errs[0]
	}

	if response.Code != 200 {
		return 0, errors.New(response.ResultMsg)
	}

	return response.Data.CallJobID, nil
}
